Suspense for Data Fetching
概要
resourceと呼ばれている「readを呼ぶと状態に合わせて適当にPromiseをthrowしたり例外をthrowしたり結果をreturnしたりする」オブジェクトをContainerから渡し、Suspenseで囲まれたコンポーネントの中でreadすると、適当にフォールバックが行われてデータの取得ができる たぶんreadでなくてgetterやProxyを使って透過的なI/Fにしてもいいんだろうと思う、destructuringとかした日には最悪なことになりそうだけど
resourceは生成されたタイミングで既に内部にPromiseを持っていることが推奨されている
できるだけ早くリクエストを飛ばすことで、遷移を速くしてUXの向上が期待できる
現在はPromiseがthrowされたら即座にフォールバックが表示されてしまうが、Concurrent ModeではuseTransitionやSuspenseListなどのプリミティブを使ってこのタイミングを制御することができる すぐにフォールバックを表示させてスピナーが出るとかではなく、少し待ってからスピナーを出す(待ち時間の間に取得が終わったらスピナーは出さずに直に遷移する)みたいな芸当ができる
気になること
アプリケーションの設計はどうなるのか?
Suspenseに代表される非同期処理の状態管理プリミティブと、それと統合して機能することが期待される「賢いデータ取得ライブラリ」が登場すれば、複雑な状態管理はほとんど不要になってしまう可能性がある よりRedux離れが進むのでは
そもそも今までReduxに頼りすぎていた部分が分解されて、あるべき場所に落ち着いている?
そもそもApolloのuseQueryとかの時点で強力だったし、そういう概念がさらに普及するとかなのでは
どこでリソースを作るのか
できるだけ上層がよさそう
Atomic Designの言葉を借りるならPageくらい上で、そこからContextを使って伝搬させてContainerでreadを呼んでPresenterに引き渡す
resourceの生成に必要な情報が下層にならないと得られないのならば、UI設計に何か問題があるということなのかもしれない
「きれいな設計には最適化の余地がある」の対偶
賢いデータ取得ライブラリって何なんだ
適当に概念を作ってしまったが
キャッシュ戦略を内包したデータ取得ライブラリなのではないかと思っている
Reduxに期待されていたことや、Apolloやswrがやっていること、つまりリポジトリ的な概念の自動化
(アプリのドメイン的な意味での)リソース、ユーザーや投稿などをkey-valueで管理して、データ取得が行われるごとに更新する。場合によっては永続化も行う
swrなんかは、ページへのフォーカス、つまりViewでのイベントをトリガーにしてキャッシュの更新を行っていたりして変態的
key-valueだけではリストやタイムラインのような順序のあるデータをうまく扱えないが、Apolloでは@clientディレクティブを使ってクライアント側でカスタムのロジックを書くことでこの問題に対処しようとしている
クライアントサイドでデータを扱うロジックを書くとサーバーサイドと二重にロジックを管理することになりがちなので、諸刃の剣だと思う、高いUXが求められる箇所でのみ認められそう
APIレスポンスは複数のリソースを含むことがある(e.g. 投稿データにユーザーの情報も含まれる)
うまくやればOpenAPI Specとかから情報を引き出して自動化できるかもしれない
これらの戦略をまとめてうまく書けるようなライブラリを作れたら天下取れるんじゃないかという気がする
DBをクライアントサイドに持ってくるの、ここまでの文脈を考えると天才的に便利だな……
備え
「非同期処理とUIのベストプラクティス」としての Suspense for Data Fetching は現在でも十分に価値がある
今からでも体験を上げるためにできることはある
現実問題として、SuspenseなしでPendingとRecededを両立させたUIを作るのは非常に骨が折れると思う どちらが適切か検討するのが妥当かもしれない
PendingなパターンはuseEffectを使った実装で、Recededなパターンは今のSuspenseでも可能
またはSkeletonにRecededの役割を持たせる?(プレースホルダだけが表示されるのを許容する)
知見を集めていく必要がある
小さいアプリケーションを作りつつ考えていきたい
現状react-domのみ。react-nativeは非対応
RNはFabric待ちなんだろうな……